﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Nest;

namespace XMK.Framework.ElasticSearch
{
    public class ElasticSearchQuery
    {
        private ElasticSearchQuery(BaseQuery searchDescriptor)
        {
            _queryDescriptor = searchDescriptor;
        }

        private BaseQuery _queryDescriptor;

        public BaseQuery QueryDescriptor
        {
            get
            {
                return _queryDescriptor;
            }
        }

        public static ElasticSearchQuery Eq(string fieldName, object value)
        {
            return new ElasticSearchQuery(Query<dynamic>.Term(fieldName, value.ToString()));
        }

        public static ElasticSearchQuery NotEq(string fieldName, object value)
        {
            return new ElasticSearchQuery(Query<dynamic>.Bool(t2 => t2.MustNot(t3 => t3.Term(fieldName, value))));
        }

        public static ElasticSearchQuery Lk(string fieldName, string value)
        {
            return Lk(fieldName, value, "ik");
        }

        public static ElasticSearchQuery Lk(string fieldName, string value, string analyzer)
        {
            //QueryDescriptor<dynamic> descriptor = new QueryDescriptor<dynamic>();
            //descriptor.Match(t2 => t2.OnField(fieldName).QueryString(value).Operator(Operator.and).Analyzer(analyzer));
            //return new ElasticSearchQuery(descriptor);
            return new ElasticSearchQuery(Query<dynamic>.Match(t2 => t2.OnField(fieldName).Query(value).Analyzer(analyzer)));
        }

        public static ElasticSearchQuery And(params ElasticSearchQuery[] esFilters)
        {
            IEnumerable<ElasticSearchQuery> queryList = esFilters.Where(item => item != null);
            if (queryList.Count() == 0)
                return null;

            List<Func<QueryDescriptor<dynamic>, BaseQuery>> funcList = new List<Func<QueryDescriptor<dynamic>, BaseQuery>>();
            foreach (var item in queryList)
            {
                funcList.Add(tt => item.QueryDescriptor);
            }

            return new ElasticSearchQuery(Query<dynamic>.Bool(t1 => t1.Must(funcList.ToArray())));
        }

        public static ElasticSearchQuery In(string fieldName, IEnumerable<string> values)
        {
            return new ElasticSearchQuery(Query<dynamic>.Terms(fieldName, values.ToArray()));
        }

        public static ElasticSearchQuery Between(string fieldName, int? from, int? to)
        {
            if (from >= to)
            {
                throw new ArgumentException("the value of argument from must less than argument to");
            }
            return new ElasticSearchQuery(Query<dynamic>.Range(t1 => t1.OnField(fieldName).From(from).To(to)));
        }

        public static ElasticSearchQuery Between(string fieldName, double? from, double? to)
        {
            if (from >= to)
            {
                throw new ArgumentException("the value of argument from must less than argument to");
            }
            return new ElasticSearchQuery(Query<dynamic>.Range(t1 => t1.OnField(fieldName).From(from).To(to)));
        }

        public static ElasticSearchQuery Between(string fieldName, DateTime? from, DateTime? to)
        {
            if (from >= to)
            {
                throw new ArgumentException("the value of argument from must less than argument to");
            }
            return new ElasticSearchQuery(Query<dynamic>.Range(t1 => t1.OnField(fieldName).From(from).To(to)));
        }

        public static ElasticSearchQuery Gt(string fieldName, int value)
        {
            return new ElasticSearchQuery(Query<dynamic>.Range(t1 => t1.OnField(fieldName).From(value).FromExclusive()));
        }

        public static ElasticSearchQuery Gt(string fieldName, double value)
        {
            return new ElasticSearchQuery(Query<dynamic>.Range(t1 => t1.OnField(fieldName).From(value).FromExclusive()));
        }

        public static ElasticSearchQuery Gt(string fieldName, DateTime value)
        {
            return new ElasticSearchQuery(Query<dynamic>.Range(t1 => t1.OnField(fieldName).From(value).FromExclusive()));
        }

        public static ElasticSearchQuery Gte(string fieldName, int value)
        {
            return new ElasticSearchQuery(Query<dynamic>.Range(t1 => t1.OnField(fieldName).From(value)));
        }

        public static ElasticSearchQuery Gte(string fieldName, double value)
        {
            return new ElasticSearchQuery(Query<dynamic>.Range(t1 => t1.OnField(fieldName).From(value)));
        }

        public static ElasticSearchQuery Gte(string fieldName, DateTime value)
        {
            return new ElasticSearchQuery(Query<dynamic>.Range(t1 => t1.OnField(fieldName).From(value)));
        }

        public static ElasticSearchQuery Lt(string fieldName, int value)
        {
            return new ElasticSearchQuery(Query<dynamic>.Range(t1 => t1.OnField(fieldName).To(value).ToExclusive()));
        }

        public static ElasticSearchQuery Lt(string fieldName, double value)
        {
            return new ElasticSearchQuery(Query<dynamic>.Range(t1 => t1.OnField(fieldName).To(value).ToExclusive()));
        }

        public static ElasticSearchQuery Lt(string fieldName, DateTime value)
        {
            return new ElasticSearchQuery(Query<dynamic>.Range(t1 => t1.OnField(fieldName).To(value).ToExclusive()));
        }

        public static ElasticSearchQuery Lte(string fieldName, int value)
        {
            return new ElasticSearchQuery(Query<dynamic>.Range(t1 => t1.OnField(fieldName).To(value)));
        }

        public static ElasticSearchQuery Lte(string fieldName, double value)
        {
            return new ElasticSearchQuery(Query<dynamic>.Range(t1 => t1.OnField(fieldName).To(value)));
        }

        public static ElasticSearchQuery Lte(string fieldName, DateTime value)
        {
            return new ElasticSearchQuery(Query<dynamic>.Range(t1 => t1.OnField(fieldName).To(value)));
        }

        public static ElasticSearchQuery MultiMatch(IEnumerable<string> fieldNames, string value)
        {
            return MultiMatch(fieldNames, value, "ik");
        }
        public static ElasticSearchQuery MultiMatch(IEnumerable<string> fieldNames, string value, string analyzer)
        {
            return new ElasticSearchQuery(
                Query<dynamic>.MultiMatch(t1 => t1.OnFields(fieldNames).Type(TextQueryType.BOOLEAN).Operator(Operator.and).Query(value).Analyzer(analyzer)));
        }
    }
}
